/**
 * WebGL 封装 - L5
 * @author lonphy
 * @version 0.1
 */
(function(L5) {
	"use strict";

	L5.WebGL = {
		vs: new Map(),      // vertex shader cache
		fs: new Map(),      // fragment shader cache
		program: new Map()  // program cache
	};
	/**
	 * 获取文件第一行注释KEY
	 * @param src
	 * @returns {String}
	 */
	function getShaderKey(src) {
		return src.split(/\s/, 1)[0];
	}
	/**
	 * 创建顶点着色器
	 * @param gl {WebGLRenderingContext}
	 * @param src {String} 顶点着色器代码
	 * @returns  {WebGLShader}
	 */
	L5.WebGL.createVertexShader = function(gl, src) {
		let key = getShaderKey(src);
		if (L5.WebGL.vs.has(key)) {
			return L5.WebGL.vs.get(key);
		}
		let shader = gl.createShader(gl.VERTEX_SHADER);
		gl.shaderSource(shader, src);
		gl.compileShader(shader);
		if(L5.DEBUG && !gl.getShaderParameter(shader, gl.COMPILE_STATUS)){
			console.error(gl.getShaderInfoLog(shader));
			return null;
		}
		shader._key = key;
		L5.WebGL.vs.set(key, shader);
		return shader;
	};
	/**
	 * 创建片元着色器
	 * @param gl {WebGLRenderingContext}
	 * @param src {String} 片元着色器代码
	 * @returns  {WebGLShader}
	 */
	L5.WebGL.createFragmentShader = function(gl, src) {
		let key = getShaderKey(src);
		if (L5.WebGL.fs.has(key)) {
			return L5.WebGL.fs.get(key);
		}
		let shader = gl.createShader(gl.FRAGMENT_SHADER);
		gl.shaderSource(shader, src);
		gl.compileShader(shader);
		if(L5.DEBUG && !gl.getShaderParameter(shader, gl.COMPILE_STATUS)){
			console.error(gl.getShaderInfoLog(shader));
			return null;
		}
		shader._key = key;
		L5.WebGL.fs.set(key, shader);
		return shader;
	};
	/**
	 * 创建着色器应用
	 * @param gl {WebGLRenderingContext}
	 * @param vs {WebGLShader} 顶点着色器
	 * @param fs {WebGLShader} 片元着色器
	 * @returns {WebGLProgram}
	 */
	L5.WebGL.createProgram = function(gl, vs, fs) {
		// 合成程序的KEY
		let k = vs._key+fs._key;
		if ( L5.WebGL.program.has(k) ) {
			return L5.WebGL.program.get(k);
		}
		//创建程序
		let program = gl.createProgram();
		gl.attachShader(program, vs);
		gl.attachShader(program, fs);

		gl.linkProgram(program);
		if (L5.DEBUG && !gl.getProgramParameter(program, gl.LINK_STATUS)) {
			throw new L5.L5Error('WebGLError', '创建程序失败');
		}
		program._key = k;
		L5.WebGL.program.set(k, program);
		return program;
	};
	/**
	 * 解析模型
	 * @param gl {WebGLRenderingContext}
	 * @param data {Object} 模型数据
	 * @param target {Object} 输出对象
	 * @return Object
	 */
	L5.WebGL.createBuffer = function(gl, data, target){
		// 创建顶点缓冲, 一个模型只使用一个
		target.vertices = gl.createBuffer();
		gl.bindBuffer(gl.ARRAY_BUFFER, target.vertices);
		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
		target.positionCount = data.length/9;   // 3 +3 +2 +1
		target.stride = 9 * 4;          // 步幅
		target.pos_offset = 0;        // 0*4 顶点数据偏移
		target.normal_offset = 3*4;     // 法线偏移
		target.uv_offset = 6 *4;        // UV偏移
		target.tex_idx_offset = 8 *4;   // 纹理索引偏移
	};

	L5.WebGL.createElementBuffer = function(gl, data, target) {
		target.indices = gl.createBuffer();
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, target.indices);
		gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(data), gl.STATIC_DRAW);
		target.indicesCount = data.length;
	};

	L5.WebGL.createReflection = function(gl, size, target) {
		target.texture = gl.createTexture();
		gl.bindTexture(gl.TEXTURE_2D, target.texture);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

		target.frameBuffer = gl.createFramebuffer();
		gl.bindFramebuffer(gl.FRAMEBUFFER, target.frameBuffer);
		gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0);

		target.renderBuffer = gl.createRenderbuffer();
		gl.bindRenderbuffer(gl.RENDERBUFFER, target.renderBuffer);
		gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size);
		gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, target.renderBuffer);

		gl.bindTexture(gl.TEXTURE_2D, null);
		gl.bindRenderbuffer(gl.RENDERBUFFER, null);
		gl.bindFramebuffer(gl.FRAMEBUFFER, null);
		target.size = size;
	};

	/**
	 * 获取程序变量
	 * @param gl {WebGLRenderingContext}
	 * @param p {WebGLProgram}
	 * @returns {Object}
	 */
	L5.WebGL.getProgramStatus = function(gl, p) {
		gl.useProgram(p);
		let attributesLength = gl.getProgramParameter(p, gl.ACTIVE_ATTRIBUTES),
			uniformsLength = gl.getProgramParameter(p, gl.ACTIVE_UNIFORMS),
			item, name,
			ret = {};

		for(let i=0; i< attributesLength; ++i){
			item = gl.getActiveAttrib(p, i);
			name = item.name;
			ret[name] = gl.getAttribLocation(p, name);
			gl.enableVertexAttribArray(ret[name]);
		}
		for(let i=0; i< uniformsLength; ++i){
			item = gl.getActiveUniform(p, i);
			name = item.name;

			ret[item.name] = gl.getUniformLocation(p, name);
		}
		return ret;
	};
})(window.L5);